home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-02 / pnl003.zip / PNL003.TXT < prev    next >
Text File  |  1990-06-26  |  112KB  |  2,195 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  
  9.  
  10.  
  11.  
  12.  
  13.                             
  14.                                                      
  15.                                                                  
  16.                                                                  
  17.                                 ////////    //    //    //   
  18.                                //    //    ///   //    //    
  19.                               //    //    ////  //    //     
  20.                              ////////    // // //    //      
  21.                             //          //  ////    //       
  22.                            //          //   ///    //          
  23.                           //          //    //    ///////    
  24.                                                                  
  25.                                                                  
  26.                                                              
  27.                                                             
  28.                                                             
  29.                                   Pascal NewsLetter         
  30.                                        Issue #3              
  31.                                       June, 1990             
  32.                                                             
  33.                                                             
  34.                                   Editor: Pete Davis         
  35.                                                             
  36.                                                             
  37.                                                             
  38.                                                             
  39.                                                             
  40.                                                             
  41.                                                             
  42.                                                             
  43.                                                             
  44.                                                             
  45.                                                             
  46.                                                             
  47.                                                                 
  48.                     The Programmer's Forum BBS is the home of
  49.                     PNL. It can be reached in Washington, DC at
  50.                     (202)966-3647. Information is available 
  51.                     through the following locations:        
  52.                                                             
  53.                     FidoNet:  Pete Davis@1:109/138           
  54.                     GEnie:    P.DAVIS5                          
  55.                     BitNet:   HJ647C@GWUVM & UE356C@GWUVM
  56.                     InterNet: HJ647C@GWUVM.GWU.EDU 
  57.                               UE356C@GWUVM.GWU.EDU
  58.                           and Pete.Davis@f138.n109.z1.fidonet.org
  59.  
  60.  
  61.                                                                           2
  62.  
  63.  
  64.                                   Table of Contents
  65.  
  66.  
  67.  
  68.  
  69.           Introduction ..................................... Page  3 (P.D.)
  70.  
  71.           Letter from Charles Falconer ..................... Page  4 (C.F.)
  72.  
  73.           A Diatribe on Structured Programming and Pascal .. Page  8 (C.F.)
  74.  
  75.           Pascal I/O Semantics ............................. Page 18 (C.F.)
  76.  
  77.           All Sorts of Sorts ............................... Page 24 (P.D.)
  78.  
  79.           For Beginners .................................... Page 29 (B.G.)
  80.  
  81.           The Object of Objects ............................ Page 35 (J.R.)
  82.  
  83.           Doing More With Strings .......................... Page 39 (G.H.)
  84.  
  85.           Bits & Pieces .................................... Page 42 (****)
  86.  
  87.           Conclusion ....................................... Page 44 (P.D.)
  88.  
  89.  
  90.  
  91.  
  92.           P.D. -> Pete Davis         (Editor, Writer)
  93.           C.F. -> Charles Falconer   (Contributing Writer)
  94.           J.R. -> Jim Reid           (Contributing Writer)
  95.           B.G. -> Bob Gowans         (Staff Writer)
  96.           G.H. -> Gerhard Hoogterp   (Contributing Writer)
  97.  
  98.           Bits & Pieces is contibuted by various readers and contributing
  99.           writers. Credit will be given in that Bits & Pieces area.
  100.  
  101.             Turbo Pascal is a registered trademark of Borland International
  102.  
  103.                                                                           3
  104.  
  105.  
  106.                                        Introduction
  107.  
  108.                Well, I'm starting on issue #3 of the PNL for an unexpected
  109.           reason. I, just minutes ago, received what must have been the toughest
  110.           criticisms I have received yet. Anyone who frequents the Pascal echo
  111.           in FidoNet knows who Charles Falconer is. I received a nice-sized
  112.           packet of files from Charles regarding the PNL. It was loaded with
  113.           constructive criticism. Some of it is already noticable. Charles
  114.           pointed out that most people will go through the PNL on the screen and
  115.           would prefer single-spaced text. Since I print it out, I was making it
  116.           look good for printouts. I think Charles is right, though, so I am
  117.           taking that advice. If there are enough people who want the double-
  118.           spaced version, I will either release them together, or I will provide
  119.           the double-spaced version to those who request it.
  120.  
  121.                Anyway, on with what Charles sent to me. His article was full of
  122.           advice and comments. I really found it helpful and as Charles wrote:
  123.           'If I agreed with everything I read there would be no point in reading
  124.           it!' I agree with that, but not everything you said.I did agree with
  125.           most of what you said, though. Hopefully the users will approve of the
  126.           changes. Anyway, along with the helpful comments, Charles included two
  127.           articles that he had written. How could I possibly refuse to include
  128.           them? Charles, thanks a lot. I really appreciate you advice and
  129.           encouragement. I also appreciate your articles. They'll help beef-up
  130.           the third issue a bit.
  131.  
  132.                Because Charles included so many good tips and because some of
  133.           them are regarding articles I wrote in the first issue, I have
  134.           included a copy of his letter so others can see what he has to say
  135.           about Generic Structures and Optimization, two articles that were
  136.           written in the first issue. 
  137.  
  138.                I meant to get to my sorting article in the last issue. Obviously
  139.           that didn't happen, so I'm putting it in this issue. I have been
  140.           blessed with 4 articles so far. I can't tell you how much these
  141.           articles help out. I think it is going to be necessary to make some
  142.           small rules for submissions, though. The rules are pretty simple:
  143.  
  144.           1> Single-Spaced
  145.           2> No justification
  146.           3> No page numbers
  147.           4> carriage returns only at end of paragraphs and where necessary  
  148.           (i.e. creating diagrams)
  149.  
  150.                I'm not going to refuse an article if it doesn't follow these
  151.           specifications, it just makes things easier for me when including it
  152.           in the newsletter.
  153.  
  154.                Well, I hope you enjoy what follows.
  155.  
  156.                                                                               4
  157.  
  158.                                Letter from Charles Falconer
  159.  
  160.           I am attaching a couple of contributions - feel free to edit them
  161.           within reason.  These have been around in various forms for a while.
  162.           Also feel free to grab anything I put on the Pascal Echo, if you wish,
  163.           (unless I have done something foolish).  It is all public domain.  If
  164.           you publish anything of mine include my Fidonet address please.
  165.  
  166.           On formatting of PNL:  (all opinion)
  167.  
  168.           These are only suggestions, after all it is your project, and I am
  169.           thankful for it.  As an aside, the results are smaller and take less
  170.           transmission time and disk space.
  171.  
  172.           I find the double spacing to be virtually unreadable on the CRT.  This
  173.           sort of thing is virtually never printed, and when it does the user
  174.           doesn't want to use a lot of paper.  Who knows, he may even have to
  175.           feed individual sheets.
  176.  
  177.           I just found these on Hippocampus, and have not really read anything
  178.           yet.
  179.  
  180.           I suggest a formatting of no more than 72, preferably 66, chars per
  181.           line, with no indentation, single spaced, with a maximum of 60
  182.           lines/page.  If lines are not right justified (minor point) the user
  183.           can easily reformat to taste.  Pages should be separated with
  184.           form-feeds, not white space, as the white space makes it very hard to
  185.           follow anything on the CRT.  For the same reason pagenumbers and the
  186.           ilk should be at page top.
  187.  
  188.           I attach PNL001 reformatted to roughly these specifications, for your
  189.           consideration.  I passed it through two filters, changed all
  190.           <eoln><eoln> into <eoln>, and did some minor hand editing afterwards.
  191.           The original contained some naked <cr>s, which didn't even overprint,
  192.           but were removed by my stripovr filter (the filters are available in
  193.           DETAB12.LZH on 141/205)
  194.  
  195.           If you feel indentation for printing is critical, I will be happy to
  196.           write a small filter to add it in.  It can also expand <ff> to a
  197.           constant 66 (or other) lines per page if needed.  (Europeans have 12
  198.           inch paper standard).  Form-feeds also serve to trigger page printing
  199.           on Laser Printers.
  200.  
  201.           I also have RNF, in Pascal, available with source, for generalized
  202.           formatting.  It can do quite a pleasant job.  RNF13AT.LZH (110k), also
  203.           on 141/205.  RNF13SOR.LZH has ISO standard source, 13AT is for Turbo
  204.           and includes the documentation and Turbo source.  The docs are a
  205.           deliberate mess, and get cleaned up by running RNF on them.
  206.  
  207.           With your permission only, I will mount the reformatted versions on
  208.           Hippocampus to replace yours.  No sweat either way. {Editors Note:
  209.           Feel free to do it.}
  210.  
  211.                                                                               5
  212.  
  213.  
  214.  
  215.  
  216.           Net mail to 141/209.1 will reach me, addressed to Charles Falconer.
  217.  
  218.           1990/5/18                             Chuck.
  219.  
  220.           ------
  221.  
  222.           ps:  I read over pnl001 and have a few minor comments:
  223.  
  224.           1.  Optimizing for size often DOES improve speed {ed. note: Yes, in 
  225.               most cases, but not all! }.  The data structure and algorithm is  
  226.               usually more important than the code.  Clarity is at the top of
  227.               my wants 99% of the time.  Do nothing without measuring the
  228.               program first - otherwise the rewards are not going to be
  229.               noticeable, but the (clarity) penalties are.  Smaller code
  230.               means more other resource available.  I have a system where
  231.               I can find sharp performance improvements for every 1k less code
  232.               space used - sometimes only 128 bytes is important.  In this
  233.               case the difference is availability of swap space in memory, and
  234.               the increment suddenly means something doesn't get swapped.
  235.           2.  Generic procs - If the body of the system deals with the two
  236.               pointer linkage item, rather than the data body, much more 
  237.               can be made generic.  Only a few rare i/o procedures will
  238.               need to know about the actual data item.  Thus 'push' would
  239.               push such a linkage record, pop would return one, and could
  240.               be a function.  Nothing need even know they are headers after
  241.               the lowest level.
  242.           3.  Fetish of mine - Pascal is ALWAYS capitalized.  A proper name.
  243.           4.  Optimizing - I virtually never turn off run time checks.  The 
  244.               exception is in the heart of loops, once well debugged.  Such
  245.               loops should have loop invariants stated and checked.  A whole
  246.               program is never debugged.
  247.           5.  I have a different view than most about formatting, some of 
  248.               which is in the attached files.
  249.  
  250.           6.  Generally excellent.  If I agreed with everything I read there
  251.               would be no point in reading it!  You seem to have pretty sound
  252.               teachers and a good mind.
  253.  
  254.           pps:
  255.  
  256.           Here is a useful tidbit for linked lists.  This only assumes the list
  257.           pointers contain a 'next' field.  Takes a single pass.  Just pass it
  258.           the root pointer.
  259.  
  260.               PROCEDURE reverse(VAR dirlist : adirptr);
  261.               (* Do a list walk and reverse the list order *)
  262.  
  263.                 VAR
  264.                   prev, pprev : adirptr;
  265.  
  266.                                                                               6
  267.  
  268.  
  269.                 BEGIN (* reverse *)
  270.                 prev := NIL;
  271.                 WHILE dirlist <> NIL DO BEGIN
  272.                   pprev := prev; prev := dirlist;
  273.                   dirlist := dirlist^.next; prev^.next := pprev; END;
  274.                 dirlist := prev;
  275.                 END; (* reverse *)
  276.  
  277.           This allows you to create a list with simple code, i.e.
  278.  
  279.               new(p); p^.next := root; root := p;
  280.               (* then set any data fields *)
  281.  
  282.           and later access in the order of input.  One example of use is in
  283.           scanning parameter lists when compiling a procedure header.  Then the
  284.           final list is used to check procedure calls correctly as they come in
  285.           from the source.
  286.  
  287.           and here is the performance of MRGSORT on my system, sorting 12 char.
  288.           random alphabetic strings (packed into pksize = 4 integers, 3 per
  289.           integer).  The whole of this was published on Pascal Echo, and is
  290.           available as MRGSORT.LZH on 1:141/205.  The MRGSORT unit operates on
  291.           singly linked lists, only requiring that 'next' be the first field.
  292.  
  293.           (* On my 8mhz V20 XT system, executes as follows:            *)
  294.           (*        items      creation time      sorting time         *)
  295.           (*        -----      -------------      ------------         *)
  296.           (*           10        0.013 Sec.         0.010 Sec.         *)
  297.           (*          100        0.117 Sec.         0.164 Sec.         *)
  298.           (*          500        0.582 Sec.         1.050 Sec.         *)
  299.           (*         2500        2.903 Sec.         6.407 Sec.         *)
  300.           (*        12500       14.502 Sec.        38.028 Sec.         *)
  301.           (* (FULL) 33874       38.028 Sec.       113.692 Sec.         *)
  302.           (* which shows the n*log(n) behaviour of the algorithm.      *)
  303.  
  304.           and using the following comparison procedure:
  305.  
  306.           {$f+}   (* passed functions MUST be far *)
  307.  
  308.             FUNCTION greater(thing, than : pointer) : boolean;
  309.             (* This is the time bind - make assy language. This *)
  310.             (* will later be passed in as a param to mrgsort    *)
  311.             
  312.               LABEL 9, 10;
  313.             
  314.               VAR
  315.                 k    : pkindex;
  316.                        (* These gyrations bypass type checking, and describe  *)
  317.                        (* the actual pointer type that mrgsort will call with *)
  318.           {}    a    : alfaptr ABSOLUTE thing;
  319.           {}    b    : alfaptr ABSOLUTE than;
  320.  
  321.                                                                               7
  322.  
  323.           {$r-,s-}
  324.               BEGIN (* greater *)
  325.               greater := true;
  326.               FOR k := pksize DOWNTO 1 DO  (* Check most sig. first *)
  327.                 IF a^.s[k] > b^.s[k] THEN GOTO 10          (* decided *)
  328.                 ELSE IF a^.s[k] < b^.s[k] THEN GOTO 9;     (* decided *)
  329.            9: greater := false;
  330.           10: END; (* greater *)
  331.  
  332.           {$r+,s+,f-}      (* put the options back *)
  333.  
  334.           This being the major time bind, it is the only place that range checks
  335.           are turned off.  As an aside, I would have used your 'generic' linkage
  336.  
  337.           method, except that it would involve an extra dereference right here
  338.           in the sensitive heart of the algorithm.  Changing to such is easy.
  339.           The {} in the lh margins mark non-standard usage.
  340.  
  341.           {Editors Note: 8 lines removed: Not of interest to readers.}
  342.  
  343.  
  344.                                                                               8
  345.  
  346.                   A diatribe on Structured Programming and Pascal
  347.            by C.B. Falconer, 680 Hartford Tpk, Hamden, Ct 06517.  281-1438
  348.            
  349.            
  350.            
  351.           Structured programming is NOT about GOTO less code, or languages,
  352.           but about the design methodology.  I use Pascal, (ISO standard
  353.           version, not Turbo, but the remarks generally apply).  You design
  354.           a program from the top down, i.e.:
  355.            
  356.           Step 1.  Write down what it is going to do, and specify the data
  357.           used.  Keep the data to an absolute minimum, because the less you
  358.           have to remember the fewer mistakes there will be:
  359.            
  360.           (I will write a simple line copying program, assuming two extensions
  361.            to standard Pascal, i.e. read(..) can read a string, and length(..)
  362.            can return the length of that string.  Most systems have these
  363.            extensions, but if not the procedures are easily created in STANDARD
  364.            Pascal)
  365.            
  366.           (For Turbo users, some additional changes have to be made.  These are
  367.            shown in a final addendum to this file.  The problems are:
  368.              1.  Turbo REQUIRES the assign operation
  369.              2.  Turbo fails to automatically close files
  370.              3.  Turbo fails to truncate string writes to the field value.
  371.              4.  Turbo uses the predefined "string" type to enable the
  372.                            read(string).
  373.            all are fairly easily handled, as can be seen in the modifications)
  374.            
  375.            -------
  376.            
  377.           PROGRAM something(infile, outfile, output);
  378.           (* using output for error messages, processing infile to outfile *)
  379.           (* Define all data types that will be used GLOBALLY or as parameters
  380.           *)
  381.            
  382.             CONSTANT
  383.               maxbuff     = 80;
  384.            
  385.             TYPE
  386.               buff        = ARRAY [1..maxbuff] OF char;
  387.            
  388.             VAR
  389.               infile,
  390.               outfile     : text;
  391.               buffer      : buff;
  392.            
  393.             BEGIN (* something *)
  394.             initialize;
  395.             WHILE NOT eof(infile) DO BEGIN
  396.               getdata(infile, buffer);
  397.               putdata(outfile, buffer); END;
  398.  
  399.                                                                               9
  400.  
  401.             cleanup;
  402.             END. (* something *)
  403.            
  404.             -------
  405.            
  406.           This models what you want to do, with no detail.  Once you have
  407.           written the other procedures (and whatever they require) you are
  408.           done.  ALL the data that is really needed is already specified.
  409.           You can add dummy procedures and check the result by compiling at
  410.           this point.  Note that, as a matter of style, all data is passed
  411.           via parameters.  This makes future changes much easier, and avoids
  412.           looking around for "what is this thing".
  413.            
  414.           Step 2: Put in dummy procedures to resolve the program.  The result
  415.           can be compiled.
  416.            
  417.            -------
  418.            
  419.           PROGRAM something(infile, outfile, output);
  420.           (* using output for error messages, processing infile to outfile *)
  421.           (* Define all data types that will be used GLOBALLY or as parameters
  422.           *)
  423.            
  424.             CONSTANT
  425.               maxbuff     = 80;
  426.            
  427.             TYPE
  428.               buff        = ARRAY [1..maxbuff] OF char;
  429.            
  430.             VAR
  431.               infile,
  432.               outfile     : text;
  433.               buffer      : buff;
  434.            
  435.             (* 1---------1 *)
  436.            
  437.             PROCEDURE initialize;
  438.            
  439.               BEGIN (* initialize *)
  440.               END; (* initialize *)
  441.            
  442.             (* 1---------1 *)
  443.            
  444.             PROCEDURE getdata(VAR infile : text; VAR buffer : buff);
  445.            
  446.               BEGIN (* getdata *)
  447.               END; (* getdata *)
  448.            
  449.             (* 1---------1 *)
  450.            
  451.             PROCEDURE putdata(VAR outfile : text, buffer : buff);
  452.            
  453.                                                                              10
  454.  
  455.               BEGIN (* putdata *)
  456.               END; (* putdata *)
  457.            
  458.             (* 1---------1 *)
  459.            
  460.             PROCEDURE cleanup;
  461.            
  462.               BEGIN (* cleanup *)
  463.               END; (* cleanup *)
  464.            
  465.             (* 1---------1 *)
  466.            
  467.             BEGIN (* something *)
  468.             initialize;
  469.             WHILE NOT eof(infile) DO BEGIN
  470.               getdata(infile, buffer);
  471.               putdata(outfile, buffer); END;
  472.             cleanup;
  473.             END. (* something *)
  474.            
  475.             -------
  476.            
  477.           Notice that each procedure is indented to show its control level,
  478.           and the BEGIN/ENDS are commented.  This will be useful when fully
  479.           expanded, and if inserted at this stage as a habit will always be
  480.           present to help.
  481.            
  482.           Notice also that each parameter is VAR only when the procedure must
  483.           be able to alter it.  In some cases this may cause a minor slowdown,
  484.           but the advantage is the GUARANTEE that errors in one procedure do
  485.           not propagate into the rest of the program.  This also allows the
  486.           parameter to be supplied by an expression (for integers, reals,
  487.           booleans, etc.), which cannot be done for a VAR parameter.  Think
  488.           of non-VAR parameters as pre-initialized data areas for the procedure,
  489.           dynamically assigned.
  490.            
  491.           Sometimes obscure bugs arise in Pascal because of failure to specify
  492.           the VAR when the parameter is to be modified.  This seems to be
  493.           mentally easy to overlook.  All file specification paramters must
  494.           always be VAR.
  495.            
  496.           You can read this program (even though it does nothing yet) and
  497.           trivially satisfy yourself that it is correct.  I.E. it will perform
  498.           the function, and will terminate.
  499.            
  500.           FROM HERE ON you will NEVER change the global part.  EVERYTHING
  501.           added will be in the 4 procedures that the global program calls.  You
  502.           may want to tweak the type definition of buffer (that is why the
  503.           constant MAXBUFF exists).
  504.            
  505.           Keeping everything simple, we will leave the cleanup procedure empty
  506.           (but another application may need it), and fill in the details for a
  507.                                                                              11
  508.  
  509.           complete program.
  510.            
  511.           Step 3: If complex, put in simple code to check that the outer
  512.           system runs the way you want it (starts, stops, etc).  Then repeat
  513.           the design process on each individual procedure if needed.  This
  514.           example is so simple that no repeat will be needed.
  515.            
  516.            -------
  517.           EXCEPT for the "readln" in GETDATA, and the "length" in PUTDATA,
  518.           this will compile and run on ANY Pascal system meeting the ISO or
  519.           ANSI standards.  Correction will involve the definition of buff,
  520.           and writing two custom procedures, at most.
  521.            
  522.           PROGRAM something(infile, outfile, output);
  523.           (* using output for error messages, processing infile to outfile *)
  524.           (* Define all data types that will be used GLOBALLY or as parameters
  525.           *)
  526.            
  527.             CONSTANT
  528.               maxbuff     = 80;
  529.            
  530.             TYPE
  531.               buff        = ARRAY [1..maxbuff] OF char;
  532.            
  533.             VAR
  534.               infile,
  535.               outfile     : text;
  536.               buffer      : buff;
  537.            
  538.             (* 1---------1 *)
  539.            
  540.             PROCEDURE initialize;
  541.             (* all that is needed to open the input and output files in standard
  542.           *)
  543.             (* Pascal.  Non-Standard systems (e.g. Turbo) may need more.        
  544.           *)
  545.            
  546.               BEGIN (* initialize *)
  547.               reset(infile);
  548.               rewrite(outfile);
  549.               END; (* initialize *)
  550.            
  551.             (* 1---------1 *)
  552.            
  553.             PROCEDURE getdata(VAR infile : text; VAR buffer : buff);
  554.             (* We might want this to read one word, as an example of a different 
  555.           *)
  556.             (* program using the same basic model, or to ignore non-numeric
  557.           input *)
  558.             (* For numeric input, we could send an error message if none found. 
  559.            *)
  560.            
  561.  
  562.                                                                              12
  563.  
  564.               BEGIN (* getdata *)
  565.               readln(infile, buffer);
  566.               END; (* getdata *)
  567.            
  568.             (* 1---------1 *)
  569.            
  570.             PROCEDURE putdata(VAR outfile : text, buffer : buff);
  571.             (* And this might want to upshift everything, or insert tabs, etc.
  572.           *)
  573.            
  574.               BEGIN (* putdata *)
  575.               writeln(outfile, buffer : length(buffer));
  576.               END; (* putdata *)
  577.            
  578.             (* 1---------1 *)
  579.            
  580.             PROCEDURE cleanup;
  581.            
  582.               BEGIN (* cleanup *)
  583.               END; (* cleanup *)
  584.            
  585.             (* 1---------1 *)
  586.            
  587.             BEGIN (* something *)
  588.             initialize;
  589.             WHILE NOT eof(infile) DO BEGIN
  590.               getdata(infile, buffer);
  591.               putdata(outfile, buffer); END;
  592.             cleanup;
  593.             END. (* something *)
  594.            
  595.             -------
  596.            
  597.           And the program is written.  Each component is so simple, and deals
  598.           with so few items, that you can be sure it is correct.  Almost all
  599.           errors will be syntax errors (omitted semi-colons, mis-spellings,
  600.           etc) which the compiler will catch for you.
  601.            
  602.           If you are writing in a non-structured language, such as assembly or
  603.           Fortran, use an outline similar to the above, and translate it into
  604.           the language you are using.  GOTO's can then be used, BUT THE FLOW
  605.           OF CONTROL is strictly structured, and thus clear.  (But there is a
  606.           place for GOTOs, even in Pascal - that is another diatribe). Similarly
  607.           the use of data items is clear, even if you have to declare other
  608.           globals to replace the local variables, because of the end language.
  609.            
  610.           Notice that, in Pascal, you are usually backing up to somewhere
  611.           between the procedure (or program) heading, and the executable code
  612.           for that block (marked by "BEGIN (* blockname *)" ) to insert the
  613.           next level.  In Pascal you never need to worry about names, because
  614.           inserted procedures are local, and the only name conflicts that can
  615.           occur are with those names shown in the header (and any local
  616.                                                                              13
  617.  
  618.           declarations).  You can see all these immediately.
  619.            
  620.           This all builds on the well known fact that human brains can normally
  621.           handle up to about 7 items simultaneously.  Once you have to worry
  622.           about more things you will miss something.  Thus, KEEP IT SIMPLE.
  623.           Build a complex system out of SIMPLE building blocks.  At any level,
  624.           you can understand what is going on.
  625.            
  626.           Pascal makes such coding very easy, but forces you to follow a
  627.           standard format (basically declare everything before using it).
  628.           The use of indentation to depict levels of control eases
  629.           understanding, i.e. to see what controls whether a statement is
  630.           executed, just follow up to the outer indentation level (this is a
  631.           convention, not a language feature).  Everything looks more or less
  632.           like
  633.            
  634.                 IF condition THEN BEGIN
  635.                   dothis;
  636.                   andthat;
  637.                   andsoforth; END
  638.                 ELSE BEGIN
  639.                   dosomethingelse
  640.                   andsoon; END;
  641.            
  642.           and you can tell at a glance what conditions will allow each group
  643.           to be executed.
  644.            
  645.           If you really must use Basic, Fortran, Cobol, and other antiques,
  646.           try writing pseudo code in a structured form, keep it as comments,
  647.           and let it define the real code you write.  When you make a change,
  648.           revise the pseudo-code (for a real change, not just a coding error),
  649.           and keep it current.
  650.            
  651.           It is not hard to write 500 or 1000 line programs that work first
  652.           shot in this manner (excepting the typos, which the compiler usually
  653.           will catch for you).
  654.            
  655.           Summary (and additions) -
  656.             KEEP EACH module SIMPLE.
  657.             Let the outer code define what each module must do.
  658.             Keep each module on one CRT screen or less.
  659.             Use parameters, even if not really needed.  (You can change to
  660.               globals for efficiency later if you have to for efficiency).
  661.             AVOID proliferation of GLOBAL variables.  Keep it SIMPLE.
  662.            
  663.           ------------------------------------------------------------------
  664.            
  665.           (For Turbo users, some additional changes have to be made.  These are
  666.            shown in a final addendum to this file.  The problems are:
  667.              1.  Turbo REQUIRES the assign operation
  668.              2.  Turbo fails to automatically close files
  669.              3.  Turbo fails to truncate string writes to the field value.
  670.                                                                              14
  671.  
  672.              4.  Turbo uses the predefined "string" type to enable the
  673.                            read(string).
  674.            all are fairly easily handled, as can be seen in the modifications)
  675.            
  676.           HERE IS THE MODIFIED PROGRAM, with changes inserted commented.
  677.           look for the "<<<" string.
  678.            
  679.            -------
  680.            
  681.           THIS Turbo VERSION will not run on an ANSI/ISO standard system.
  682.            
  683.           PROGRAM something(infile, outfile, output);
  684.           (* using output for error messages, processing infile to outfile *)
  685.           (* Define all data types that will be used GLOBALLY or as parameters
  686.           *)
  687.            
  688.             CONSTANT
  689.               maxbuff     = 80;
  690.            
  691.             TYPE
  692.               buff        = string[maxbuff];          (* <<< CHANGED *)
  693.                       (*      ^   *)
  694.                       (*      ^-- one of the worst choices in Turbo is *)
  695.                       (* that "string" is a reserved word (rather than *)
  696.                       (* a predefined type.  This causes all sorts of  *)
  697.                       (* nuisances in porting standard Pascal to Turbo.*)
  698.            
  699.             VAR
  700.               infile,
  701.               outfile     : text;
  702.               buffer      : buff;
  703.            
  704.             (* 1---------1 *)
  705.            
  706.             PROCEDURE initialize;
  707.             (* all that is needed to open the input and output files in standard
  708.           *)
  709.             (* Pascal.  Non-Standard systems (e.g. Turbo) may need more.        
  710.           *)
  711.            
  712.               (* 2---------2 *)
  713.            
  714.               PROCEDURE attachfile(VAR f : text; position : integer);   (* <<
  715.           ADD *)
  716.               (* attach the Pascal file to the commandline parameter *)
  717.               (* in position "position" of the run-time command *)
  718.            
  719.               (* A style note: An IF THEN .. ELSE .. clause should        *)
  720.               (* normally be written with the longer clause in the ELSE   *)
  721.               (* part.  This makes it easy to see the flow of control. A  *)
  722.               (* short ELSE clause 28 pages down is easily missed, not to *)
  723.               (* mention the nuisance of deciding which IF it goes with.  *)
  724.                                                                              15
  725.  
  726.            
  727.                 BEGIN (* attachfile *)
  728.                 IF position <= paramcount THEN assign(f, paramstr(position))
  729.                 ELSE BEGIN
  730.                   writeln('Need file #', position : 1, ' specification');
  731.                   halt; END;
  732.                 END; (* attachfile *)
  733.            
  734.               (* 2---------2 *)
  735.            
  736.               BEGIN (* initialize *)
  737.               attachfile(infile, 1); attachfile(outfile, 2);     (* << ADDED *)
  738.               reset(infile);
  739.               rewrite(outfile);
  740.               END; (* initialize *)
  741.            
  742.             (* 1---------1 *)
  743.            
  744.             PROCEDURE getdata(VAR infile : text; VAR buffer : buff);
  745.             (* We might want this to read one word, as an example of a different 
  746.           *)
  747.             (* program using the same basic model, or to ignore non-numeric
  748.           input *)
  749.             (* For numeric input, we could send an error message if none found. 
  750.            *)
  751.            
  752.             (* Instead of using the Turbo string type, we could have *)(* <<
  753.           NOTE *)
  754.             (* made a different buff definition, such as:            *)
  755.             (*    buff = RECORD                                      *)
  756.             (*      lgh  : integer;                                  *)
  757.             (*      data : ARRAY[1..maxbuff] OF char;                *)
  758.             (*      END;                                             *)
  759.             (* and altered this procedure to read into it, setting   *)
  760.             (* the lgh value.  Then the putdata would have needed    *)
  761.             (* only minor modification, such as:                     *)
  762.             (*    writeln(buffer.data : buffer.lgh);                 *)
  763.             (* except that Turbo fails to use the field correctly.   *)
  764.            
  765.               BEGIN (* getdata *)
  766.               readln(infile, buffer);
  767.               END; (* getdata *)
  768.            
  769.             (* 1---------1 *)
  770.            
  771.             PROCEDURE putdata(VAR outfile : text, buffer : buff);
  772.             (* And this might want to upshift everything, or insert tabs, etc.
  773.           *)
  774.            
  775.               BEGIN (* putdata *)
  776.               writeln(outfile, buffer : length(buffer));           (* << NOTE *)
  777.               (* For Turbo strings we can omit the " : length(buffer)" *)
  778.                                                                              16
  779.  
  780.               (* clause above.  If the buff type was still really an   *)
  781.               (* array of char we would need something like :          *)
  782.               (*    FOR i := 1 TO length(buffer) DO                    *)
  783.               (*      write(f, buffer[i];                              *)
  784.               (* to compensate for the Turbo failure to truncate.      *)
  785.               END; (* putdata *)
  786.            
  787.             (* 1---------1 *)
  788.            
  789.             PROCEDURE cleanup;
  790.            
  791.               BEGIN (* cleanup *)
  792.               close(outfile);              (* << ADDED - Turbo doesnt automate
  793.           *)
  794.               END; (* cleanup *)
  795.            
  796.             (* 1---------1 *)
  797.            
  798.             BEGIN (* something *)          (* << The outer block doesnt change
  799.           *)
  800.             initialize;
  801.             WHILE NOT eof(infile) DO BEGIN
  802.               getdata(infile, buffer);
  803.               putdata(outfile, buffer); END;
  804.             cleanup;
  805.             END. (* something *)
  806.            
  807.             -------
  808.            
  809.           More style notes:  BEGIN and END are used to delimit compound
  810.           statements in Pascal, and not to show control flow.  Modula uses
  811.           END to show the end of controlled statements, and implies the BEGIN
  812.           after IF, WHILE, etc.  Thus I feel extra indentations for BEGINs
  813.           are pure confusion (and lead to programs that run off the right of
  814.           the page), and subordinate them.  I also usually attach the END to
  815.           the end of the controlled code, as shown, and use a separate line
  816.           only when multiple ENDS must appear.  This helps to keep code
  817.           vertically compact, so that the whole control flow can be seen at
  818.           a glance.  In Pascal BEGIN END really delimit blocks only when
  819.           used at the start and finish of PROCEDURE or FUNCTION code.
  820.            
  821.           Similarly, CASE labels are really LABELS, and belong at the left of
  822.           the source listing.  They are not controlled statements, but
  823.           reference points to which control flows, eg:
  824.            
  825.                     CASE ch : char OF
  826.           'A', 'a':   dothingswitha;
  827.           'B', 'b':   dothingswithb;
  828.           'C':        BEGIN
  829.                       makeanoise;
  830.                       dothingswithbigC;
  831.                       END;
  832.                                                                              17
  833.  
  834.           'c':        dothingswithlittlec;
  835.                       END; (* case *)
  836.            
  837.           and, on reading, it is quite obvious that only one path will be
  838.           followed, and how to find that path.
  839.  
  840.  
  841.                                                                              18
  842.  
  843.                      PASCAL I/O semantics, File PASCALIO.DOC
  844.                 C.B. Falconer 85/9/11, 87/2/12, 88/11/20, 89/12/12
  845.  
  846.           This is an explanation of the action of Pascal I/O, as applied to
  847.           text  files.   A  system  meeting the ISO and ANSI  standards  is
  848.           assumed.  This  does not apply to Turbo Pascal  exactly,  because
  849.           Turbo  omits  some  of  the  standard  abilities  and  functions,
  850.           especially  for console input  (but Turbo 4  up is closer).  UCSD
  851.           Pascal fails in console i/o, but other operations are implemented.
  852.           PascalP functions exactly as described below.
  853.  
  854.             REMEMBER - THIS IS ANSI/ISO STANDARD PASCAL.   The standard has
  855.           been published and  in effect since 1983.   The standard does NOT
  856.           forbid extensions, but does insist on compliance.   In addition a
  857.           system meeting the standard MUST have a way of  disabling any and
  858.           all extensions, so that source can be checked for portability.
  859.  
  860.           Any  Pascal  file is conceptually a single stream,  with  a  file
  861.           buffer variable.   If we always refer to the file variable itself
  862.           as "f",  the buffer variable is "f^".   If f is declared as "f  :
  863.           FILE  OF thing",  then f^ is of type "thing",  and may be used as
  864.           such a variable at any time the file is open (i.e. after the file
  865.           has been reset or rewritten).
  866.  
  867.           A  Pascal text file is equivalent to "PACKED FILE OF  char",  and
  868.           additionally specifies that the eoln,  readln, writeln procedures
  869.           may be used. THESE MAY NOT BE USED ON A NON-TEXT FILE.
  870.  
  871.           Reading
  872.           -------
  873.  
  874.           For reading, a file at any time consists of two ordered arrays of
  875.           items.  The first is the portion that has already been input, and
  876.           the  second  is the portion that has not  been  input  yet.   The
  877.           buffer  variable  f^ always contains the last single  item  input
  878.           (consisting of characters, an eof mark, and an eoln mark for text
  879.           files).   The eoln mark always appears as a space in f^,  and may
  880.           only be detected by the eoln procedure.  The eof mark in any non-
  881.           empty  text file must immediately follow an eoln mark  (specified
  882.           by  the  standard).   (Thus  any good system  will  automatically
  883.           append  an  eoln  on closing a file,  if and only if  it  is  not
  884.           already  present.)  The second portion of the file is  unlimited,
  885.           and unknown as yet to the Pascal program.
  886.  
  887.           When a file is "reset" the file is actually opened, and the first
  888.           char is placed in f^ (this may be the eof or eoln  mark,  checked
  889.           by  eof/eoln  functions).  This  first char is removed  from  the
  890.           second portion.
  891.  
  892.           If reset is applied to an already open file, the effect is always
  893.           to rewind it (if possible). Obviously some files cannot be reset,
  894.           e.g. it is hard to make the console repeat its previous sequence,
  895.                                                                              19
  896.  
  897.           and thus "reset(input)" may be an error on some systems.
  898.  
  899.           From here on,  the action of the "get(f)" procedure is to advance
  900.           one further character in the source file,  discarding the old  f^
  901.           value,  and replacing it with the next char.  It should always be
  902.           an error to do this when eof is true.
  903.  
  904.           Note  that  nothing has yet affected any variable in  the  Pascal
  905.           program,   except  the  f^  buffer.   These  are  the  underlying
  906.           functions  of the input system.   The program may use the file by
  907.           such actions as "ch := f^" at any time.
  908.  
  909.           The  syntax of "read(f,  ch)" is STRICTLY defined as "ch  :=  f^;
  910.           get(f)",  and  the eoln and eof functions examine the non-visible
  911.           characteristics of the last input character.   If "f" is omitted,
  912.           as  in "read(ch)" the standard file "input" is assumed,  and  the
  913.           buffer variable is "input^".
  914.  
  915.           For  most CPM or MSDOS systems the file actually contains a  <cr>
  916.           to mark eoln,  and a <^Z> to mark eof.   The value of f^ when eof
  917.           is true is not defined by the standards, but when eoln is true it
  918.           should be a space. Thus the <cr> character can not appear (unless
  919.           the system defines eoln as the <cr,lf> pair.  Some systems always
  920.           discard any <lf>,  so that the file action remains the same  when
  921.           input from a keyboard as when input from a disk file.
  922.  
  923.           The syntax of "read(f, ch1, ch2, ..)" is defined as "read(f,ch1);
  924.           read(f,ch2);  ....  ",  and is simply a shorthand.  If the object
  925.           read-into is an integer,  or a real, then automatic conversion is
  926.           performed  from  a text string,  and at completion f^  holds  the
  927.           terminating  character (space,  non-numeric,  etc).   Such a read
  928.           causes  a  run-time error when no valid  integer  etc.  is  found
  929.           before  a terminator,  but leading blanks (and eolns) are skipped
  930.           over.
  931.  
  932.           Notice that nothing so far controls any flushing of input  lines,
  933.           to ensure that a read starts on the next physical line.   This is
  934.           performed by "readln(f)",  which is defined as "WHILE NOT eoln(f)
  935.           DO  get(f);  get(f)".  NOTE the final get.   This always leave f^
  936.           holding the first character of the next line (which is a space if
  937.           the next line is empty, i.e. consists of eoln alone), or possibly
  938.           an eof mark. Again, an omitted "f" implies input.
  939.  
  940.           The syntax of "readln(f,  item1,  item2, .. itemn)" is defined as
  941.           "read(f,item1); read(f,item2); ... read(f,itemn); readln(f)", and
  942.           is again just a convenient shorthand.
  943.  
  944.           Interactive files
  945.           -----------------
  946.  
  947.           This brings up the great bugaboo of Pascal text i/o:  When a file
  948.           is reset it MUST place the first character in f^. If that file is
  949.                                                                              20
  950.  
  951.           interactive (i.e. the keyboard) the first character must be typed
  952.           at that time.  Thus the natural sequence "reset(f); write('prompt
  953.           message');  read(f, ch)" to get a reply to a prompt requires that
  954.           the answer be typed before the prompt is made.  The problem  also
  955.           reappears after any readln, because the first "get" from the next
  956.           line is performed. (see below for why f^ is filled at all)
  957.  
  958.           This  is  normally  cured  by a special driver  for  text  files.
  959.           Whenever  the  "get" is executed it simply sets a  flag  somehere
  960.           (totally invisible to the application program) which says "a  get
  961.           is  pending".  (If  get  finds the flag set it must  perform  the
  962.           pending get,  and then again set the flag).   Note that the "get"
  963.           may be implied by a reset,  read,  or readln operation.  Now  the
  964.           system  must  again intercept any use of eoln,  eof,  or  the  f^
  965.           variable   and,   before  actually  executing  them,   check  the
  966.           "get_pending" flag.  If set the actual get must be performed, the
  967.           flag reset,  and then the eoln,  eof,  f^ references may be made.
  968.           This  prevents  the  early  physical  read,  and  allows  natural
  969.           programming.   However the programmer should always remember that
  970.           any reference to eof,  eoln,  or f^ will cause the physical read.
  971.           Thus   the  sequence  "reset(f);    IF  eof(f)  THEN   something;
  972.           write('prompt');  read(f,ch)" will cause the physical read to  be
  973.           too early.
  974.  
  975.           Some systems (e.g. UCSD) do not follow the ANSI/ISO standard, and
  976.           define  a  special  interactive  file  type where read(f,  ch) is
  977.           defined as "get(f); ch := f^". This causes all sorts of problems,
  978.           because  the  programmer  must  always  know that  this  file  is
  979.           interactive, and  programs  cannot  use  the standard  input  and
  980.           disk files interchangably.
  981.  
  982.           The  "get" is normally executed on reset (or readln) so that  the
  983.           value  of  eoln and eof is available after using a character  (by
  984.           read),  and  so  that  the program can look  ahead  to  the  next
  985.           character.  This  allows  decisions  to  be  made,  i.e.  is  the
  986.           following character numeric..  then read a number; or is it alpha
  987.           ..  then  read  a char;  or is it a special ..  then read a  user
  988.           command etc. Thus a file copy program such as:
  989.  
  990.                  WHILE NOT eof DO BEGIN
  991.                    WHILE NOT eoln DO BEGIN
  992.                      read(ch); write(ch); END;
  993.                    readln; writeln; END;
  994.  
  995.           works naturally.  The read/write line can be replaced by
  996.  
  997.                      write(input^); get(input); END
  998.  
  999.           or by some sort of filter such as
  1000.  
  1001.                      IF input^ <> ' ' THEN write(input^);
  1002.                      get(input); END;
  1003.                                                                              21
  1004.  
  1005.           to strip out all blanks ith the same action and no auxiliary variable. 
  1006.           Such a fragment  can  copy  the  standard input  to  standard  output, 
  1007.           and  works correctly with any i/o redirection applied.
  1008.  
  1009.           NOTE that "reset(input)" is always automatically performed when a
  1010.           program  begins running,  and similarly  "rewrite(output)".  Thus
  1011.           such statements should normally not appear in a program.
  1012.  
  1013.           Think  of readln as a line-flushing procedure,  but bear in  mind
  1014.           that "readln(item)" is always equivalent to "read(item); readln".
  1015.  
  1016.           Writing
  1017.           -------
  1018.  
  1019.           Again, all files consist of 2 parts,  that which has been written
  1020.           (and is in the external file), and that which has not.  The  next
  1021.           item to be written is ALWAYS in f^, and "put(f)" is defined to do
  1022.           the writing, and leave f^ contents undefined  (in practice,  most
  1023.           systems leave f^ unchanged).
  1024.  
  1025.           Similar to read, "write(f, item)" is STRICTLY defined  to be  the
  1026.           sequence "f^ := item; put(f)".  For text files ONLY,  writeln can
  1027.           put an eoln mark in the external file.   Most systems,  including
  1028.           PascalP, can in practice create an  eoln mark by writing suitable
  1029.           characters, BUT THIS IS NOT portable.
  1030.  
  1031.           Write(f, item1, item2, .. itemn) is  STRICTLY  defined  as  being
  1032.           "write(f,item1);  write(f,  item2);  ...  write(f,  itemn)",  and
  1033.           "writeln(f,  item)" is defined as "write(f,  item);  writeln(f)".
  1034.           Both  of these are again shorthand.   The writeln procedure alone
  1035.           (i.e.  writeln(f) ) simply puts an eoln mark into the file  being
  1036.           written.   If  the  "f"  specification is omitted  the  write  is
  1037.           shipped to "output" file by default.
  1038.  
  1039.           Again,  the  fundamental  writing procedure  is  "put(f)",  which
  1040.           causes the content of f^ to be appended to the end of the file f.
  1041.           "write(f,  item) is STRICTLY defined as "f^ := item; put(f)", and
  1042.           should be unable to create the eoln mark in a text file (reserved
  1043.           for  writeln).   The  action of "rewrite(f)" is to empty any  old
  1044.           version of f,  and leave f^ undefined. f^ is also undefined after
  1045.           any write operation.  Thus doing nothing except "rewrite(f)" in a
  1046.           program should leave f as an empty file, but existing.
  1047.  
  1048.           All Pascal files should be automatically closed when the defining
  1049.           program (or procedure for a local file) is exited.   Some systems
  1050.           provide  a  "close"  procedure to force an early  close  for  one
  1051.           reason or another (e.g.  to release a locked file to another user
  1052.           in  a multi-process environment).   If a file was open for  write
  1053.           (via rewrite),  and is later "reset", an automatic close is done.
  1054.           These closings of a written file append the eof mark,  and  force
  1055.           any  system buffers to be flushed.   Some systems are incomplete,
  1056.           and  actually  require that a specific call to "close"  be  made.
  1057.                                                                              22
  1058.  
  1059.           This  procedure is non-standard,  and such programs will  not  be
  1060.           portable.
  1061.  
  1062.           Text file writes
  1063.           ----------------
  1064.  
  1065.           The standard specifies the formatting abilities for various types
  1066.           of objects.  The use of fields for integers and reals is complied
  1067.           with in general, however
  1068.  
  1069.                   write(f, astring : field)
  1070.  
  1071.           is defined to RIGHT justify astring in  field positions,  AND  TO
  1072.           TRUNCATE astring (on the right) when it is longer than field.  An
  1073.           item of type astring is compatible with PACKED ARRAY[1..] OF char.
  1074.           Failure to do this truncation is a major impediment to portablity
  1075.           in Turbo Pascal.
  1076.  
  1077.           To harp on the action  of writeln,  this marks the end of a  text
  1078.           line and usually flushes any buffers.   The actual implementation
  1079.           of  the file system  should not  matter,  provided it  meets  the
  1080.           abstract requirements of Pascal.   Thus systems that never put an
  1081.           eoln marker on the disk,  but simply retain pointers to  the line
  1082.           endings, should function correctly.
  1083.  
  1084.  
  1085.           Fixes
  1086.           -----
  1087.  
  1088.           Again, this is how it should work according to international (and
  1089.           ANSI) standards. Some systems do not meet the standards - beware.
  1090.  
  1091.           The so-called string type in  Turbo and UCSD Pascal is not really
  1092.           necessary, although it is often a convenience.  It is possible to
  1093.           create systems that are fully Standard compatible, and still have
  1094.           string reads, concatenation, dynamic length, extraction, etc. All
  1095.           such operations are available in PascalP as extended system  pro-
  1096.           cedures, and thus porting to another system only requires writing
  1097.           such procedures.  When not provided as part of the system package
  1098.           efficiency may suffer, but no logical change in the program  will
  1099.           be needed.
  1100.  
  1101.           For this reason I suggest that Turbo users should ALWAYS use  the
  1102.           concat function for strings, rather than the "+" operator.   When
  1103.           this is done the program can be converted fairly easily to an ISO
  1104.           standard system.
  1105.  
  1106.           For  Turbo  Pascal  users,  I have written a  set  of  includable
  1107.           procedures or units  (see TURBOFIX.LBR  or TURBOFIX.ARC  for TP3,
  1108.           TXTFInnn.LZH for TP4 up,  with nnn  121  at present)  which  make
  1109.           Turbo  meet  these  standards,  although  you  will  have to  use
  1110.           non-standard procedure names.  These are available without charge
  1111.                                                                              23
  1112.  
  1113.           for non-commercial use.
  1114.  
  1115.           I hope this clears up some confusion.
  1116.  
  1117.  
  1118.                                                                              24
  1119.  
  1120.                                     All Sorts of Sorts
  1121.                                        By Pete Davis
  1122.  
  1123.                Every programming student comes across sorting at one time or
  1124.           another. Occasionally, one comes across sorting in their own work.
  1125.           Picking the right sort for the job isn't always an easy process. Many
  1126.           things need to be taken into consideration. First of all, what will
  1127.           the typical size for the data be? Some sorts work better for a lot of
  1128.           data and others work better with small amounts. Other factors include
  1129.           knowing what kind of data-structure you're working with. If you're
  1130.           using a linked list, certain sorts might not be worth the trouble, but
  1131.           if you're using an array, it might be ok to use those sorts.
  1132.  
  1133.                I want to offer a range of sorts here. Each one will include a
  1134.           short algorithm and some code examples will be included with this
  1135.           issue of PNL. With each sort, I'll give a description of how it works,
  1136.           what it's good points are and what it's problems are. I'll explain
  1137.           what kind of applications it is best for and when to avoid it. There
  1138.           are many programming books that go into a lot of depth on sorting, so
  1139.           if you really want to get into the meat of sorting, I suggest you
  1140.           check out your public library or local bookstore.
  1141.  
  1142.                There are several ways to measure the quality of a sorts. Average
  1143.           number of comparisons and average number of exchanges are very common
  1144.           to get an idea of how much work the sort has to do for a particular
  1145.           amount of data. i.e. average number of comparisons for 100 items in a
  1146.           bubble sort is about 5000, depending on exactly how the algorithm is
  1147.           implemented. Other important factors are the actual time it took to
  1148.           execute the sort and memory requirments for the sort. 
  1149.  
  1150.           A. Bubble Sort
  1151.           --------------
  1152.                Talk about basic, the bubble sort is about the most basic and
  1153.           easy to understand of the sorts. It's simplicity gives way to slow
  1154.           execution and many comparisons. For small amounts of data (i.e. 100 or
  1155.           fewer data items) the bubble sort will usually suffice. The exact
  1156.           amount of data really depends on the size of the data-items and the
  1157.           algorithm used. The only time where the bubble sort is the best sort,
  1158.           is if the data is already in order. Otherwise, chances are, most other
  1159.           sorts will beat the bubble sort, especially if the lowest value is
  1160.           near the end of the list or the highest value is near the beginning of
  1161.           the list.
  1162.  
  1163.                The bubble sort uses the simple concept of going through a list
  1164.           and checking each item against the item next to it. If they are out of
  1165.           order, then put them in order. It keeps repeating this process until
  1166.           it reaches the end of the list. Then it starts over at the beginning
  1167.           of the list again, and keeps repeating this whole process until no
  1168.           more items are switched. You can either check to see if no more items
  1169.           are switched or you can go through N-1 times where N is the number of
  1170.           items in the list. The prefered method is to check for whether or not
  1171.           anything is switched. This means that if the list is already in order,
  1172.                                                                              25
  1173.  
  1174.           you won't have redundant passes through the list. The following will
  1175.           show a group of characters out of order. I will then show what would
  1176.           happen with each pass of the bubble sort.
  1177.  
  1178.           START         -> F   E   R   M   T   A   P 
  1179.           STEPS: { E&F SWITCH : F&R IN ORDER : R&M SWITCH 
  1180.                    R&T IN ORDER : T&A SWITCH : P&T SWITCH }
  1181.           END OF PASS 1 -> E   F   M   R   A   P   T   { # exchanges: 4 }
  1182.           END OF PASS 2 -> E   F   M   A   P   R   T   { # exchanges: 2 }
  1183.           END OF PASS 3 -> E   F   A   M   P   R   T   { # exchanges: 1 }
  1184.           END OF PASS 4 -> E   A   F   M   P   R   T   { # exchanges: 1 }
  1185.           END OF PASS 5 -> A   E   F   M   P   R   T   { # exchanges: 1 }
  1186.  
  1187.                I only showed all of the steps for the first pass. I believe it
  1188.           is straight-foward enough that it was all that was necessary. You can
  1189.           examine the code for more examples. Notice how much work it took to
  1190.           sort only 7 items, though. there were 5 passes, and each pass
  1191.           consisted of 6 comparisons and at most, 4 exchanges and at best, 1
  1192.           exchange with a total of 9 exchanges and 30 comparisons. This isn't a
  1193.           worse case scenario, but it is what I will compare several of the
  1194.           sorts against. After that, we'll take some actual results from our
  1195.           test program.
  1196.  
  1197.  
  1198.           B. Selection Sort
  1199.           -----------------
  1200.                The selection sort is kind of like putting a hand of playing
  1201.           cards in order. First thing you do is look at your whole list. You
  1202.           take the lowest value and put it in the beginning. Then you take the
  1203.           next lowest value and put it right after the first. (Or you could take
  1204.           the highest and then the next highest and do it backwards, it really
  1205.           doesn't matter.)
  1206.  
  1207.                I don't think any sort of diagrams or algorithms need to be
  1208.           explained for this. I think everyone is familiar with this technique.
  1209.           Although the selection sort isn't incredibly fast, it is very simple
  1210.           and does give a marginal improvement over the bubble sort, in general.
  1211.  
  1212.           C. Insertion Sort
  1213.           -----------------
  1214.                The insertion sort can also use the idea of a hand of playing
  1215.           cards, but instead of working with all of your cards at once, you take
  1216.           a card one at a time and insert it where it belong as you get it. The
  1217.           insertion sort is fairly simple, but has some problems. The insertion
  1218.           sort is ideal for linked lists. If an insetion needs to be made, all
  1219.           you have to do is re-direct some pointers. The insertion sort is much
  1220.           less powerful when used with arrays, or contiguous lists. The problem
  1221.           is that when you insert a new value, chances are you'll average moving
  1222.           about half of the data in the list over one space. When your list gets
  1223.           long, that can cause major problems. Each time something is inserted,
  1224.           everything in the list would have to shift over. 
  1225.                                                                              26
  1226.  
  1227.                The insertion sort, like the selection sort is very straight-
  1228.           foward and simple, so I'll just let you examine the code if you have
  1229.           any more questions.
  1230.  
  1231.           D. Shell Sort
  1232.           -------------
  1233.                The shell sort uses the idea of sorting over an increment. Let's
  1234.           use a new list of data:  F  E  R  M  T  A  P  G  N  Y  C
  1235.           and we'll take an increment of three. In our first step, we will
  1236.           compare item #1 with item #4 (1+increment of 3) then 2 and 5 and make
  1237.           exchanges over the increment. Let's see the results after 1 pass:
  1238.  
  1239.           F  E  A  M  G  N  P  C  R  Y  T
  1240.  
  1241.                We continue sorting with the increment of 3 until everything for
  1242.           that increment is in order. So, for the next pass we get:
  1243.  
  1244.           F  E  A  M  C  N  P  G  R  Y  T
  1245.  
  1246.                and the third step:
  1247.  
  1248.           F  C  A  M  E  N  P  G  R  Y  T
  1249.  
  1250.                now, everything is in order over the increment of 3, so we drop
  1251.           our increment to 2:
  1252.  
  1253.           A  C  E  M  F  G  P  N  R  Y  T
  1254.  
  1255.                and one more pass:
  1256.  
  1257.           A  C  E  G  F  M  P  N  R  Y  T
  1258.  
  1259.                now that that's in order, we drop to the final level with an
  1260.           increment of 1. At this point, a single pass will put everything in
  1261.           order:
  1262.  
  1263.           A  C  E  F  G  M  N  P  R  T  Y
  1264.  
  1265.                For larger amounts of data the results are a bit more dramatic.
  1266.           The choice of a starting increment of 3 and a decrement of 1 for each
  1267.           pass was completely ambiguous on my part. You can use any starting
  1268.           increment and any decrement per pass that you want. The final pass
  1269.           must be an increment of 1, however. With larger amounts of data, a
  1270.           starting increment of 5 or higher will be more useful, and keeping the
  1271.           space as an odd number for each pass is more efficient.
  1272.  
  1273.                The shell sort is a bit more complicated than the sorts shown
  1274.           previously but the average gain in speed is tens of times better than
  1275.           any of the previous sorts.
  1276.                                                                              27
  1277.  
  1278.           E. Merge Sort
  1279.           -------------
  1280.                Although the concept behind the Merge Sort is fairly simple, the
  1281.           actual coding of the sort is a bit more complex than one would expect.
  1282.           In simple terms, the Merge Sort breaks your data in half and then
  1283.           sorts each half. After the halves are sorted it puts them back
  1284.           together. It's a bit more complex in that the routine calls itself
  1285.           again and breaks each of the half-piles into halves, and so on and so
  1286.           on until each pile has either 1 or no items.
  1287.  
  1288.                You might be wondering why this is so quick, but think of it this
  1289.           way, the Bubble Sort is called a quadratic sort. That means that if
  1290.           you double the data to be sorted, it takes more than double the amount
  1291.           of time to execute the sort. So, it would be quicker to break a big
  1292.           set of data into two sets of data and sort them. The only extra time
  1293.           you'd need is to put them back together in order. The results are a
  1294.           bit more dramatic than that, though, as the piles keep getting broken
  1295.           down more and more making each individual sort incredibly quick. 
  1296.  
  1297.                The Merge Sort works well with either contiguous data (arrays) or
  1298.           linked lists. It's a great general purpose sort, but for small amounts
  1299.           (less than 100 items) of data, it probably isn't worth the effort. The
  1300.           only real drawbacks to the Merge Sort is that it requires double the
  1301.           amount of space for data to make copies of the data. Another is that,
  1302.           because it's recursive, it incurs a bit of overhead on speed and
  1303.           space. This, however, isn't incredibly significant, however, when
  1304.           comparing speeds with the previous sorts.
  1305.  
  1306.           F. Quick Sort
  1307.           -------------
  1308.                The Quick Sort is generally recognized as the best general-
  1309.           purpose sorting algorithm. It is much like Merge Sort in that the data
  1310.           is recursively broken into two pieces. The first step in the Quick
  1311.           Sort is to come up with a mid-value for your data. With numbers this
  1312.           is pretty easy but strings and characters might require a bit more
  1313.           effort. The way you come up with the mid-value can vary. The method
  1314.           I'm going to use in the sample provided is to take the mean of the
  1315.           first and last value in the list. It doesn't have to be the exact
  1316.           middle, but the more accurate it is, the faster the sort. If you have
  1317.           some sort of pre-knowledge of what your data will be like, you might
  1318.           be able to come up with a more accurate method to finding the mid-
  1319.           point. 
  1320.  
  1321.                The next step is to move all values lower than the mid-point to
  1322.           the left (or lower end of your list) of the mid-point and all the
  1323.           higher values to the right. Then you keep recursively splitting the
  1324.           left and right in half, moving the values to the left and right side
  1325.           of the mid-point, appropriately. You keep doing this until you are
  1326.           down to 1 or 0 elements in the left and right. At this point, your 
  1327.           data is in order.
  1328.                                                                              28
  1329.  
  1330.           Summary
  1331.           -------
  1332.                 The main point of this wasn't to go completely in-depth
  1333.           explaining the subtelties of each individual sort, but more to give an
  1334.           overview of each sort. I wanted the readers to be able to get a basic
  1335.           idea of how each sort works, find its advantages and dis-advantages,
  1336.           and be able to decide which sort will work best for your particular
  1337.           application.
  1338.  
  1339.                I'll leave most of the more technical explanations in the inline
  1340.           documentation of the sort unit I am providing. The test program gives
  1341.           you some stats on each sort that I have explained above.
  1342.  
  1343.                These routines that I am providing are not necessarily the
  1344.           fastest or most efficient algorithms. Everyone has their own minor
  1345.           variations on certain sorts and you may want to change them to suit
  1346.           your purposes. 
  1347.            
  1348.                                                                              29
  1349.  
  1350.                                        For Beginners
  1351.                                        By Bob Gowans
  1352.             
  1353.                In the last issue of PNL (no.2) the beginner's column discussed a
  1354.           simple but complete Pascal program in which the use of the Pascal
  1355.           standard procedures writeln and write were highlighted. The rules
  1356.           governing identifiers were also put to you. Continuing on this theme I
  1357.           would like to show how you can build on this basic layout, and produce
  1358.           a more substantial program. 
  1359.             
  1360.                Who has not heard of data? In this day and age it seems that
  1361.           there is an overwhelming amount of data available on all sorts of
  1362.           subjects. Our computer systems manipulate data - they take data in,
  1363.           process it and churn it out and there you have it, your electricity
  1364.           bill! As programmers we are mainly concerned with the manipulation of
  1365.           data, we write programs that can do all sorts of things with data and
  1366.           that produce data as results. But what exactly is data and how can we,
  1367.           as prospective programmers, make use of such data that is suitable for
  1368.           computers. Data comes in many forms, the actual word data means
  1369.           'things given', an item of data represents some fact, observation or
  1370.           idea. We humans can recognize all sorts of data easily - text,
  1371.           numbers, pictures and speech to mention but a few. However, the poor
  1372.           computer can only, in most cases, accept data in the form of symbols
  1373.           such as characters and numbers, they are picking up mind you and there
  1374.           are devices that enable the input of sound and pictures to computers.
  1375.           Even with this restricted set of characters and numbers a huge range
  1376.           of data is available as input to the computer. For example, two
  1377.           characters can represent true and false, digits allow the computer to
  1378.           use integer numbers, a decimal point with digits means the computer
  1379.           can use real numbers,characters will allow us humans to input
  1380.           languages ( such as Pascal ) into the computer. Once the data is in
  1381.           the computer it can be processed and this is done according to sets of
  1382.           instructions or algorithms. This is where we come in, we want to be
  1383.           able to write algorithms that can manipulate the data that is
  1384.           available. 
  1385.             
  1386.                'What data is available?', might be a question you would be
  1387.           justified in asking. Well, Pascal has several different inbuilt types
  1388.           of data and also there is a facility for creating your own data types
  1389.           so you have plenty to go by. In Pascal the values True and False make
  1390.           up the BOOLEAN data type, whole numbers constitute the type INTEGER,
  1391.           decimal numbers are represented by REAL data types and characters are
  1392.           represented by the CHAR type. If this seems a little fuzzy to you it
  1393.           will soon become clear once you learn to implement the various data
  1394.           types in a Pascal program. Lets do that, sticking to the
  1395.           implementation of the integer type for now. 
  1396.             
  1397.                Briefly, the store manager wants you to write a program that will
  1398.           calculate the total number of customers that use his store each day
  1399.           and output to the screen the total number of customers and the sub
  1400.           totals of female and male customers. You are given the respective male
  1401.           and female customer subtotals at the end of each day. In the following
  1402.                                                                              30
  1403.  
  1404.           program note how the lines are indented, if you copy this layout your
  1405.           programs will be more readable, but more about that later. Also note
  1406.           that we have introduced a new Pascal reserved word VAR, it is after
  1407.           this statement that variables are declared ie. the data types of the
  1408.           variables are declared. Do not worry about variables for the time
  1409.           being as we will again deal with these later. However, note that we
  1410.           can assign values to variables using the symbol :=  this is a very
  1411.           important and fundamental feature of Pascal. 
  1412.  
  1413.           program add_up; { Program heading } 
  1414.             
  1415.           var 
  1416.             
  1417.              female : integer; 
  1418.              male   : integer; 
  1419.              total  : integer; 
  1420.             
  1421.           begin 
  1422.              female := 250; 
  1423.              male   := 101; 
  1424.              writeln('The total number of customers today was ',total); 
  1425.              writeln('The number of male customers was ',male); 
  1426.              writeln('The number of female customers was ',female) 
  1427.           end. 
  1428.             
  1429.                In the program we have three variables which are declared to be
  1430.           of type integer, that is to say that the values we are going to give
  1431.           to these variables must be of an integer data type. Variables are
  1432.           declared following the Pascal reserved word VAR and are given a data
  1433.           type as follows 
  1434.             
  1435.                variable : datatype; 
  1436.             
  1437.           We could have written the variable declarations in our program as
  1438.           follows 
  1439.             
  1440.                female,male,total : integer 
  1441.             
  1442.                Each variable is separated by a comma then comes a colon before
  1443.           the data type. As the variables are of type integer, the computer now
  1444.           knows what type of data to store in them and will reserve space at a
  1445.           memory location for three integer data types, and this is crucial - it
  1446.           cannot store any other type of data in the locations it has reserved
  1447.           for our three variables. If, for example, we tried to give female a
  1448.           value of 1.5 then the computer would go haywire ( at least the
  1449.           computer knows there is no such a thing as half a female ). Seriously
  1450.           what would happen is that the computer would issue an error message
  1451.           and the program would probably abort, which would not be to good if
  1452.           you had just spent the last half hour entering data. At this point it
  1453.           would be as well to define the data type integer. 
  1454.             
  1455.                INTEGER - the positive and negative whole numbers. 
  1456.                                                                              31
  1457.  
  1458.             
  1459.                Incidentally the range of integers that you will be able to use
  1460.           depends on your computer/compiler, the range for Turbo Pascal using a
  1461.           640K RAM IBM Compatible is 32767 to -32768 for those who are
  1462.           interested. 
  1463.             
  1464.                The situation with our program is that we have declared three
  1465.           variables of type integer and now we are going to write some
  1466.           statements in our program that can play around with these variables -
  1467.           make them do some work for us! We can think of a variable as a memory
  1468.           location, with an attached name or identifier which the computer uses
  1469.           to access the contents of the variable. The rules for naming variables
  1470.           are the same that apply to naming identifiers which were discussed in
  1471.           the last issue of PNL. Why are they called variables? because as the
  1472.           name variable infers they can be updated or given new values. If we
  1473.           look at the program add_up we can see that female has been given a
  1474.           value of 250, male a value of 101 and total a value of the sum of male
  1475.           and female but these values are not fixed values as the program is
  1476.           updated every day so the values of male, female and total will change.
  1477.           In the program we say we have assigned a value of 250 to female and
  1478.           assigned a value of 101 to male. Finally we have assigned the value of
  1479.           the sum of male and female to total and written out the results. 
  1480.  
  1481.                With each program that you write it is a good idea to plan a data
  1482.           table. Choosing the right data structures for variables and deciding
  1483.           which is the right data type to use is sometimes the programmers most
  1484.           difficult task, a data table can assist you greatly in helping to make
  1485.           things more clear. Lets write a data table for our program - in later
  1486.           issues you will be made to realise that it is better to plan and
  1487.           design the program first before writing the actual code. 
  1488.             
  1489.            Identifier ( variable)   Brief description          Data type 
  1490.             
  1491.             male                    holds current total of 
  1492.                                     male customers.             integer 
  1493.             
  1494.             female                  holds current total of 
  1495.                                     female customers             integer 
  1496.             
  1497.             total                    holds the current total 
  1498.                                      of male + female             integer 
  1499.             
  1500.                You will have no doubt noted from the program that the value of a
  1501.           variable can be output to the screen, or to a printer or a file for
  1502.           that matter, and that this is done by using the writeln statement
  1503.           typically as follows 
  1504.             
  1505.                 writeln(variablename); 
  1506.             
  1507.                This will have the effect of outputting to the screen the current
  1508.           value stored in the variable. The screen output from our program would
  1509.           thus be:
  1510.                                                                              32
  1511.  
  1512.             
  1513.           The total number of customers was 351 
  1514.           The number of male customers was 101 
  1515.           The number of female customers was 250 
  1516.             
  1517.                At the same time as outputting our variables we also took the
  1518.           opportunity to output a relevant textual comment. The string that we
  1519.           want to output must be in quotes and separated from the variable name
  1520.           by a comma (,) and the whole writeln statement is enclosed in
  1521.           brackets. I wonder if you noticed that there is space inserted between
  1522.           the last character in the textline and the final quotation mark in the
  1523.           writeln statement, the space is placed there so that the output from
  1524.           the variable is not written directly at the end of the text line, such
  1525.           as : The number of female customers was205 -  resulting in messy
  1526.           screen output. A small point but well formatted text output is a must
  1527.           for today's user friendly programs. 
  1528.             
  1529.                The assignment statement can do more than just give a single
  1530.           value to a variable, the assignment statement in Pascal has the
  1531.           following form : 
  1532.             
  1533.                 variable := expression 
  1534.             
  1535.                When  the computer executes such a statement, the expression on
  1536.           the right-hand side of the assignment operator (:=) is evaluated and
  1537.           the value is given to the variable on the left-hand side. If it helps
  1538.           you try reading the assignment operator as 'becomes' ie variable
  1539.           becomes expression. 
  1540.             
  1541.                In this article we have learnt how to develop our programming
  1542.           skills by realising that the declaration and correct use of data types
  1543.           is an essential an important part of program development and that if a
  1544.           data type is declared the it can only be used for the purpose ie. data
  1545.           for which it was intended. We also discovered how to make assignment
  1546.           statements and how to perform certain operations on variables
  1547.           including writing them out to the standard output ( screen ). In the
  1548.           next article we will further expand on these basic concepts and
  1549.           hopefully introduce to you how to read in values to variables, by user
  1550.           input. 
  1551.             
  1552.                The answer to the exercise given in the last article of PNL is :
  1553.  
  1554.             
  1555.           writeln(''How many times have I told you, don''t do that;she said'');
  1556.  
  1557.             
  1558.                This shows you that if you want to output text in quotation marks
  1559.           then you must double up on quotation marks in the writeln statement. 
  1560.             
  1561.                                                                              33
  1562.  
  1563.           Self Test 
  1564.           ---- ---- 
  1565.             
  1566.           (a) The following sequence of statements appears in a pascal program.
  1567.           All variables are declared to be of type integer. 
  1568.             
  1569.           apples := 10; 
  1570.           oranges := 12; 
  1571.           bananas := 6; 
  1572.           fruit := oranges + bananas - apples; 
  1573.           apples := fruit - apples; 
  1574.             
  1575.            Write out the final value of fruit, apples, oranges and bananas. 
  1576.             
  1577.           (b) The variable number is declared to be of type integer. Which of
  1578.           the following Pascal statements are valid : 
  1579.             
  1580.           (1) number := 10; 
  1581.           (2) number := number + 1; 
  1582.           (3) 100 := number; 
  1583.           (4) number = 100; 
  1584.           (5) number := 23.5; 
  1585.           (6) number := 100 + 15 - 205; 
  1586.             
  1587.           (C) You are asked to write a program that counts the number of
  1588.           automobiles that are sold from a showroom. What data type would you
  1589.           choose to represent the total number of cars sold? How would you
  1590.           implement this problem in Pascal? 
  1591.             
  1592.             
  1593.           Solutions 
  1594.           --------- 
  1595.             
  1596.           (a) fruit = 28, apples = 18, oranges = 12, bananas = 6. 
  1597.             
  1598.             
  1599.           (b) (1) valid. 
  1600.               (2) valid. 
  1601.               (3) invalid ( you can only assign a value to a variable if they
  1602.           are on the 
  1603.                              left of the assignment operator). 
  1604.               (4) invalid ( the assignment operator is :=  ). 
  1605.               (5) invalid ( number is of type integer and you cannot assign to
  1606.           it a real 
  1607.                             value ). 
  1608.               (6) valid. 
  1609.             
  1610.           (c) integer as automobiles are best represented by whole numbers. 
  1611.             
  1612.               program car_add; 
  1613.             
  1614.               var 
  1615.                                                                              34
  1616.  
  1617.                  total,autos : integer; 
  1618.               begin 
  1619.                  total := total + autos; 
  1620.                  writeln('The total automobiles sold are ',total) 
  1621.               end. 
  1622.             
  1623.                Obviously this program is incomplete as we require some method of
  1624.           inputting the automobile data into the variable autos. This would be
  1625.           done by writing prompts to the screen so that the salesman could enter
  1626.           information, the program would read in such information. We will cover
  1627.           this in the next article. 
  1628.             
  1629.               
  1630.             
  1631.           For fun 
  1632.           ------- 
  1633.                The following program is intended for user's of Turbo Pascal only
  1634.           and makes use of the Turbo Pascal crt unit to produce sound on your
  1635.           PC's internal speaker. The main program is incorporated in a loop.
  1636.           Sound is used to get the attention or make the user aware of errors or
  1637.           as a security measure to deter unwanted users operating the system. As
  1638.           we become more proficient we will be able to put these advanced
  1639.           features to better use in our programs. 
  1640.             
  1641.               
  1642.           program alarm; 
  1643.             
  1644.           uses crt; 
  1645.             
  1646.           var 
  1647.             
  1648.              i : integer; 
  1649.             
  1650.             
  1651.           begin 
  1652.                   for i := 1 to 100 do  { loop start } 
  1653.                     begin 
  1654.                       sound(1500); 
  1655.                       delay(10); 
  1656.                       sound(500); 
  1657.                       delay(500); 
  1658.                       nosound; 
  1659.                       delay(1500) 
  1660.                     end                 { loop finish } 
  1661.             
  1662.           end. 
  1663.             
  1664.             
  1665.             
  1666.                                                 Bob Gowans 
  1667.                                                                              35
  1668.  
  1669.                                    The Object of Objects
  1670.                                         By Jim Reid
  1671.            
  1672.              With version 5.5 of Turbo Pascal, Borland added one of the newest
  1673.           features in modern programming languages--the concept of objects.  The
  1674.           good news is that object-oriented Pascal programming is a major step
  1675.           forward for programmers.  The bad news is that if you don't already
  1676.           know something about object- oriented programming (OOP for short),
  1677.           Borland's version 5.5 OOP Guide won't help you very much.  The first
  1678.           page of Chapter 1, for example, drops on you such household concepts
  1679.           as "encapsulation", "inheritance", and "polymorphism."  Ugh!  I hope
  1680.           this short article can help a bit by talking about objects more
  1681.           plainly. 
  1682.            
  1683.              So what is an object anyway?  An object is a group of Pascal
  1684.           variables (of any type) and a group of functions and procedures that
  1685.           operate on them.  In short, it is a programming technique that lets
  1686.           you create new conceptual data types (like CIRCLES) and new conceptual
  1687.           operators (like DRAW or SHRINK) for them. 
  1688.  
  1689.              Here's a simple example.  One way to define a window area on your
  1690.           display screen is by specifying two coordinates--the upper left (X,Y)
  1691.           position and the lower right (X,Y) position.  So, you might think of a
  1692.           WINDOW_AREA as an object with four variables. Here's how you would
  1693.           start to define this as an object. 
  1694.            
  1695.           Type 
  1696.                Window_Area =  Object 
  1697.                                    Upper_X , 
  1698.                                    Upper_Y , 
  1699.                                    Lower_X , 
  1700.                                    Lower_Y : byte; 
  1701.                                    {...more to follow here later...} 
  1702.                               End; 
  1703.            
  1704.              As you can see, an object looks a little like a RECORD TYPE. 
  1705.           But there's nothing strange or unfamiliar about how you define 
  1706.           the variables of an object.  You use the same type of definitions 
  1707.           you would use in the VAR statement. 
  1708.            
  1709.              If this were all that objects had to offer, you'd wonder what all
  1710.           the fuss was over them.  But defining the data variables of an object
  1711.           is only the first part of the job.  Next, you define the procedures
  1712.           and functions that can operate on these variables. Using our example,
  1713.           suppose you wanted to have one procedure that sets the window
  1714.           coordinates, another procedure that defines and clears the windowed
  1715.           area on the screen, and a third procedure to disable it.  Let's expand
  1716.           the object definition a bit further to do this: 
  1717.            
  1718.  
  1719.                                                                              36
  1720.  
  1721.  
  1722.           Type 
  1723.                Window_Area =  Object 
  1724.                                    Upper_X , 
  1725.                                    Upper_Y , 
  1726.                                    Lower_X , 
  1727.                                    Lower_Y : byte; 
  1728.                                    Procedure Init (byte X1, Y1, X2, Y2); 
  1729.                                    Procedure Enable; 
  1730.                                    Procedure Done; 
  1731.                               End; 
  1732.            
  1733.           Procedure Window_Area.Init (byte X1, Y1, X2, Y2); 
  1734.           Begin 
  1735.                Upper_X := X1; 
  1736.                Upper_Y := Y1; 
  1737.                Lower_X := X2; 
  1738.                Lower_Y := Y2; 
  1739.           End; 
  1740.            
  1741.           Procedure Window_Area.Enable; 
  1742.           Begin 
  1743.                Window(Upper_X,Upper_Y,Lower_X,Lower_Y); 
  1744.                ClrScr; 
  1745.           End; 
  1746.            
  1747.           Procedure Window_Area.Done; 
  1748.           Begin 
  1749.                Upper_X := 1; 
  1750.                Upper_Y := 1; 
  1751.                Lower_X := 80; 
  1752.                Lower_Y := 25; 
  1753.                Window(1,1,80,25); 
  1754.           End; 
  1755.            
  1756.              Notice several things about the object's definition now. First, the
  1757.           object TYPE defines not only the variables but also a set of
  1758.           procedures.  The PROCEDURE definitions look just the way you would
  1759.           define them in the INTERFACE portion of a Turbo Pascal UNIT--that is,
  1760.           you define the name and parameters of the procedure, but not the
  1761.           statements in it. 
  1762.            
  1763.              Later in your program, below the object definition, you include the
  1764.           body of each of these procedures.  Notice that each of the procedure
  1765.           names is prefixed with the name of the object type ("Window_Area" in
  1766.           this case).  The procedures (or functions) defined for an object
  1767.           automatically have access to the variables of that object.  Thus,
  1768.           these procedures can refer to "Upper_X" without having to qualify
  1769.           where that variable was defined. 
  1770.            
  1771.              Within the body of an object's procedures, things look the same as
  1772.           usual.  These procedures can be passed variables, or not. They can do
  1773.                                                                              37
  1774.  
  1775.           anything that any typical Pascal procedure can do. They are simply
  1776.           linked to their object's variables by reference. 
  1777.            
  1778.              There's nothing magical about the names INIT and DONE, but Turbo
  1779.           Pascal's programming convention suggests that you name the procedure
  1780.           which initially defines an object's variables as INIT, and the
  1781.           procedure which finally terminates the object as DONE.  If you don't
  1782.           like those names, you are free to use whatever names you prefer. 
  1783.            
  1784.              Now that you've defined the object TYPE and its procedures, to
  1785.           actually define an instance of the object (like our Window_Area) you
  1786.           simply define it as a VAR.  For example:  
  1787.  
  1788.           Var 
  1789.                My_Window : Window_Area; 
  1790.            
  1791.              To use your defined object, you execute one of the object's defined
  1792.           procedures or functions.  Here's a short example: 
  1793.            
  1794.           My_Window.Init(20,5,60,20); 
  1795.           My_Window.Enable; 
  1796.           WriteLn('See.  It worked!'); 
  1797.           Delay(1000); 
  1798.           My_Window.Done; 
  1799.            
  1800.           This example would define the window as the area between (20,5) and
  1801.           (60,20), enable the window and clear it, write a short message in the
  1802.           window display area, pause briefly, then reset the window as the
  1803.           entire screen. 
  1804.            
  1805.              Notice that you invoke an object's procedures just like any other
  1806.           Pascal procedures, but you prefix the procedure name with the name of
  1807.           a specific object variable ("My_Window" in this case). 
  1808.            
  1809.              This may seem a little odd at first, but the concept is fairly
  1810.           simple.  Think of an object as a RECORD variable that is tightly
  1811.           linked to a set of procedures and functions.  Think of invoking an
  1812.           object's procedure as if you had simply called the procedure normally,
  1813.           passing it all the defined parameters plus the object's record
  1814.           variable.  If you think of it in that way, you can see that this much
  1815.           of Turbo Pascal's object oriented programming extension is simply a
  1816.           shorthand method for passing record variables to procedures. 
  1817.            
  1818.              There is much, much more to objects than this, however. Objects can
  1819.           be constructed out of the variables and procedures of other objects. 
  1820.           For example, if you were writing a graphics program, you might define
  1821.           a POINT as an object.  The point has a single (X,Y) coordinate.  You
  1822.           might define a CIRCLE object as a POINT plus a radius.  And you might
  1823.           define a SPHERE object as a CIRCLE plus a 3-Dimension boolean flag. 
  1824.           The advantage which OOP offers you is that each object can be built on
  1825.           the foundation laid by the predecessor objects.  That is, higher level
  1826.           objects inherit the data variables and procedures of lower level
  1827.                                                                              38
  1828.  
  1829.           objects on which they are defined.  Objects also let you define to the
  1830.           procedure at execution time which objects they will act on. (This
  1831.           feature is called dynamic methods and polymorphism.)  I'll try to
  1832.           write more on these concepts in a later article. 
  1833.            
  1834.              The bottom line is that object-oriented programming can be used to
  1835.           make your programs more flexible and easier to test.  By
  1836.           "encapsulating" the variables of an object and the procedures that
  1837.           operate on them, you simplify the debugging process.  By building
  1838.           layers of objects, you simplify the coding process by reusing
  1839.           functions and procedures of predecessor objects. Eventually, after
  1840.           enough use of objects, this technique will change the way you
  1841.           structure and design your programs.  You will learn to think first
  1842.           about the structure of your data, and second about the functions you
  1843.           perform on the data. 
  1844.            
  1845.              If you'd like to see a longer example of using objects, I have
  1846.           included TP unit named TEXTLIST.ZIP.  This unit can be used to build
  1847.           and manage a linked list of textual values.  You might use this to
  1848.           build a simple editor, for example.  Enjoy, and start becoming
  1849.           familiar with Turbo Pascal's object-oriented programming! 
  1850.  
  1851.                                                                              39
  1852.  
  1853.                                   Doing More With Strings
  1854.                                     By Gerhard Hoogterp
  1855.                                      Fidonet 2:283/1.2
  1856.                                   BitNet HOOGTERP@HENUT5
  1857.                                                                                 
  1858.                     
  1859.                One of the things most programmers who switch from Basic to
  1860.           Pascal notice first is the limited number of procedures and functions
  1861.           Turbo Pascal has available to work with strings. Standard Pascal, not
  1862.           having strings at all is even worse. Actually it's been a long time
  1863.           since I programmed in Basic, but the need for some more advanced
  1864.           string routines was there when I was working on a text adventure. My
  1865.           string toolbox grew and became more advanced over the years, and so it
  1866.           evolved into what I present here.
  1867.  
  1868.                For my purposes, I defined a string as a list of tokens separated
  1869.           by a delimiter. A sentence like: 
  1870.  
  1871.                This is a sentence, with seven words.                            
  1872.                     
  1873.                    ^  ^ ^        ^^    ^     ^     ^^end of string              
  1874.                     
  1875.                                                                                 
  1876.                     
  1877.                Contains seven tokens and 4 delimiters. At some places the
  1878.           delimiters are double, like the ', ' combination. The fourth delimiter
  1879.           is the end of string Which, although not explicitly used by the
  1880.           routines, is there anyhow.
  1881.  
  1882.  
  1883.                As the toolbox was intended for use with a natural language
  1884.           parser I couldn't put restrictions on the delimiters, or the way they
  1885.           should be used. So the first routine to write was
  1886.  
  1887.  
  1888.               Procedure SimplifyDelimiters( Var TokenList  : String;            
  1889.                                            Delimiters : String);                
  1890.                
  1891.                                                                                 
  1892.                     
  1893.                It takes a string and changes double delimiters into single
  1894.           delimiters. So the ', ' combination would be replaced with only 
  1895.           space.
  1896.  
  1897.  
  1898.           To use this function with the above example would be:
  1899.  
  1900.  
  1901.             Sentence:='This is a sentence, with seven words.'; 
  1902.             SimplifyDelimiters(Sentence,' ,.');
  1903.                                                                              40
  1904.  
  1905.                The second function needed was a way to separate the string into
  1906.           a head and a tail. To find the first token. This token was of course
  1907.           delimited by a delimiter again.
  1908.  
  1909.             Function FindToken(Var TokenList  : String;                         
  1910.                               Delimiters : String):String;                      
  1911.                
  1912.                                                                                 
  1913.                     
  1914.           When this function is used on the example sentence like
  1915.  
  1916.              Sentence:='This is a sentence, with seven words.'
  1917.  
  1918.              Token:=FindToken(Sentence,' ,.');
  1919.  
  1920.  
  1921.           it will return the string 'This'. The delimiter is removed and the
  1922.           sentence becomes 'is a sentence, with seven words.'
  1923.  
  1924.  
  1925.                These two routines provide the user with a lot of power when, for
  1926.           example, reading configuration files. SimplifyDelimiters accepts a
  1927.           string in a user readable way and turns it into something more
  1928.           suitable for a computer, the FindToken takes the first token (the
  1929.           keyword in a CFG file) which can be converted to a number or a
  1930.           subrange type to use in a CASE Statement. 
  1931.  
  1932.           To make life a little easier there are some functions in the toolbox
  1933.           that alter the complete string too. Of course there are the  
  1934.  
  1935.             UpStr(Var TokenList : String) and    
  1936.             DownStr(Var TokenList : String)
  1937.  
  1938.  
  1939.           functions to turn a string in all uppercase/lowercase, a
  1940.  
  1941.             SkipLeadingSpaces(Var TokenList : String)
  1942.  
  1943.           Which deletes the leading spaces (Spaces are almost always used as
  1944.           delimiters, so leaving them there would, even after a
  1945.           SimplifyDelimiters, always let the string start with an empty token)
  1946.  
  1947.             DeleteTrailingSpaces(Var TokenList : String)                    
  1948.                Which deletes the trailing spaces of a string for the same reason
  1949.           as the SkipLeadingSpaces function. That leaves only two procedures in
  1950.           the toolbox, which are useful in the original set up of the unit.  
  1951.                          
  1952.             DeleteNoise(Var TokenList : String; Noise : String);                
  1953.                
  1954.  
  1955.                Deletes all the characters in the NOISE string from the
  1956.           TokenList. When the user is free to type what he likes (as in an
  1957.                                                                              41
  1958.  
  1959.           adventure game) there are always characters which shouldn't be there.
  1960.           DeleteNoise deletes those characters. It's even more useful when used
  1961.           together with the other left procedure
  1962.                           
  1963.             ReplaceToken( Var TokenList : String;                               
  1964.                               Tok1      : String;                               
  1965.                               Tok2      : String);                              
  1966.                     
  1967.                                                                                 
  1968.                     
  1969.           which is used to change a certain token to an other token or
  1970.           character.. For example, in a typical adventure sentence one could
  1971.           type:
  1972.  
  1973.             'Take the blue sword and go to the north'                       
  1974.                In this sentence the token 'AND' is a delimiter. It separated two
  1975.           commands. So it would be useful to change the 'AND' in for example '&'
  1976.           which can be used by the FindToken to break the sentence in two
  1977.           pieces.
  1978.  
  1979.               Sentence:='TAKE THE BLUE SWORD AND GO TO THE NORTH';
  1980.               ReplaceToken(Sentence,
  1981.                            'AND',
  1982.                            '&');
  1983.  
  1984.           would do the trick. There are also some words in the sentence that
  1985.           don't add any information to the command. Their only used because it's
  1986.           english. The words 'THE' and 'TO' can be removed from the sentence. So
  1987.           with
  1988.  
  1989.             Sentence:='Take the blue sword and go to the north'; 
  1990.             ReplaceToken(Sentence,'THE',' ');
  1991.             ReplaceToken(Sentence,'TO',' ');
  1992.             ReplaceToken(Sentence,'AND','&');
  1993.             SimplifyDelimiters(Sentence,' ');
  1994.  
  1995.  
  1996.           Results in: Sentence = 'Take blue sword & go north'
  1997.  
  1998.  
  1999.           which is more suitable for a computer than the original sentence. An
  2000.           other approach is to change all the "noise" words to a noise character
  2001.           and delete that character with the delete noise procedure.
  2002.  
  2003.                                                                              42
  2004.  
  2005.                                        Bits & Pieces
  2006.  
  2007.                Bits & Pieces is going to be a sort of gathering ground for small
  2008.           routines and things that readers or maybe even me will contribute to.
  2009.           It's basically quick and dirty routines that can't really make up a
  2010.           whole article. Individual authors and programmers will be given credit
  2011.           with their routines. This issues Bits & Pieces is going to be a bit
  2012.           scarce, having only one item, but I think it will give readers an idea
  2013.           of the kinds of things I'm looking for in it and maybe get them to
  2014.           contribute to it.
  2015.  
  2016.  
  2017.                          Bits & Pieces #1 : Nathan S. Phillips
  2018.              +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2019.  
  2020.            
  2021.                Here is a procedure to display a number with commas (12345
  2022.           becomes 12,345).  I wrote this procedure some time ago for my "DSIZ -
  2023.           Directory Size Utility" program.  The program displays the size of a
  2024.           directory (among many other things), and a display like "C:\FOO -
  2025.           13245336 bytes" would be a little confusing - is that 1, 13, or 132
  2026.           megs?  But display the sizes with commas, such as "C:\FOO - 13,245,336
  2027.           bytes", and the user can easily see how big the directory is.  But
  2028.           enough history - on to how the procedure does what it does.  The
  2029.           procedure takes the number you want to display with commas in a value
  2030.           parameter of type real.  It uses the real type so that large values
  2031.           may be passed - only the integer portion of the number is used.
  2032.           Basically, it takes a number and either: 
  2033.            
  2034.                     1.   Displays the number if it doesn't need 
  2035.                          any commas (0-999) 
  2036.                     2.   Calls itself, passing the number divided 
  2037.                          by 1000, if the number needs a comma 
  2038.                          (greater than 999) 
  2039.            
  2040.           When the procedure calls itself, the remaining instructions are
  2041.           "stacked", and executed when the call is complete.  Therefore, the
  2042.           procedure keeps calling itself (without displaying anything) until it
  2043.           gets to the leftmost digit(s) that are displayed before the first
  2044.           comma.  It displays that portion, and returns.  Then the stacked
  2045.           instructions start executing, printing the commas and zero-padded
  2046.           numbers.  When all of the stacked instructions have been executed, the
  2047.           entire number will have been printed. 
  2048.            
  2049.           Like many recursive procedures, it is an elegant, compact solution to
  2050.           the problem.  And, like many recursive procedures, it is difficult to
  2051.           follow, especially if you don't use recursion often.  (I should say
  2052.           difficult for Pascal programmers to follow; Lisp programmers *think*
  2053.           recursively.)  
  2054.            
  2055.                                                                              43
  2056.  
  2057.           procedure DisplayWithCommas(r : real);  { displays 1024 as 1,024 }  
  2058.             var t : real;                                                    
  2059.             begin       {  NON-RECURSIVE CASE if r is less than 1000 } 
  2060.               if r < 1000 then { if this part is under a thousand, it doesn't  }
  2061.                 write(r:1:0)   { need zero padding or commas, so just print it }
  2062.                                    { (This would be the 1 in 1,024) } 
  2063.               else  
  2064.                 begin  { RECURSIVE CASE - will need at least one comma } 
  2065.                                                    { call this procedure again }
  2066.                   DisplayWithCommas(int(r/1000));  { with the same number, but }
  2067.                                                    { without the last 3 digits }
  2068.                   write(',');  { display the comma } 
  2069.                   t := r - int(r/1000)*1000;{get the value of the last 3 digits}
  2070.  
  2071.                                             { (will be 24 for 1024)            }
  2072.                   if t < 100 then write('0');{pad with 0s so the routine will} 
  2073.                   if t < 10 then write('0'); { print 1,024 rather than 1,24  } 
  2074.                    write(t:1:0); {now just write the value of the last 3 digits}
  2075.                 end; 
  2076.             end;  {  procedure DisplayWithCommas  } 
  2077.            
  2078.                                                                              44
  2079.  
  2080.                                         Conclusion
  2081.  
  2082.                I like to do things in order. I wrote the introduction first
  2083.           thing, and I'm finishing off with the Conclusion, after everything
  2084.           else has been put togather. At this point, I'm speechless. I would
  2085.           like to thank all of the wonderful people who contributed to this
  2086.           issue and previous issues. We had a lot of article submitted this
  2087.           month. If people can keep sending them in, the Pascal NewsLetter might
  2088.           really gain some momentum.
  2089.  
  2090.                I hope you've enjoyed this issue as much as I have. I've enjoyed
  2091.           reading all of the articles and I've enjoyed putting them together for
  2092.           you. I've been blown away by all the contibuted articles. It's really
  2093.           been exciting to see the response. I am constantly getting
  2094.           suggestions, comments, and good criticism for the newsletter. I'm glad
  2095.           there are so many people out there who enjoy it. It makes it worth my
  2096.           time. 
  2097.  
  2098.                I'm not really sure what I'm going to do for the fourth issue. I
  2099.           do have some ideas written down here and there, but nothing firm yet.
  2100.           I'm sure users will keep sending in the articles which will keep us
  2101.           alive. If I had to rely on myself for each issue, I can assure you
  2102.           they would only come out once every two months, and wouldn't be nearly
  2103.           as good. I think I'm going to be able to put new issues out about once
  2104.           every 3 or 4 weeks, which to me seems reasonable. If you'd like to see
  2105.           it come out more often, then pitch in and send in some articles.
  2106.  
  2107.                I'm still open to contributed articles. Please send them in. I
  2108.           ask only one thing more: Please do not send the documents in
  2109.           formatted. It is almost impossible to work with the documents which
  2110.           are justified, double-spaced, etc... Please send them in single-
  2111.           spaced and hard returns only at paragraph breaks. I'll take care of
  2112.           the rest once it's integrated into the newsletter.
  2113.  
  2114.                Again, I would like to thank everyone, and please keep the
  2115.           comments and suggestions coming, but more importantly, keep the
  2116.           article submissions comming!!!
  2117.  
  2118.                                                 _Pete Davis
  2119.                                                 Editor
  2120.  
  2121.                                                                              45
  2122.  
  2123.  
  2124.                The  Pascal NewsLetter  is  Copyrighted by  Pete Davis.
  2125.                Articles submitted by others are  the property of those
  2126.                authors and are  used with permission. They  may not be
  2127.                treated  seperately  from this  newsletter  without the
  2128.                author's permission and thus maintain all  distribution
  2129.                rules of the  newsletter as a  whole. It may be  freely
  2130.                distributed  in   un-modified  form,   but  no   charge
  2131.                whatsoever may be  incurred on the recipient.  All code
  2132.                is provided 'as-is' with no guarantees whatsoever.
  2133.  
  2134.                The  Pascal  NewsLetter   can  be  obtained  from   the
  2135.                following locations:
  2136.  
  2137.                GEnie : General Electric Network for Information       
  2138.                        Exchange. It is located in the IBMPC filelist.
  2139.  
  2140.                Simtel: Internet address: 26.2.0.74 or Simtel20.ARPA It 
  2141.                        is located in the <MSDOS.PASCAL> directory.
  2142.  
  2143.                Programmer's Forum : This is the home of the PNL. Each
  2144.                                     issue can be found in the MAG     
  2145.                                     directory from the main area.
  2146.                                     The number is on the title page.
  2147.  
  2148.                If  you  would like  to  receive  back  issues  of  PNL
  2149.                directly  from  me,  send  a  diskette  and  $2.00  for
  2150.                shipping. Don't forget to include your address.
  2151.                Send your order to:
  2152.                   Peter Davis
  2153.                   4851 Brandywine St. NW
  2154.                   Washington, DC   20016
  2155.  
  2156.                If you are  a SysOp that  will regularly carry PNL  and
  2157.                would like to  have your bulletin board listed as such,
  2158.                here, send me a message either by postal mail or at one
  2159.                of the electronic  addresses given  on the title  page,
  2160.                with your bulletin board's name, phone number, and your
  2161.                name.
  2162.                                                                         46
  2163.  
  2164.                                   Distribution List
  2165.  
  2166.                The following  is the phone numbers to bulletin boards known
  2167.           to carry  PNL. If you would  like your bulletin board's  name and
  2168.           number added  to  or deleted  from this  list, please  send me  a
  2169.           message at one of my many addresses. I can not guarantee whether
  2170.           a listed board will have any particular issue, however.
  2171.  
  2172.           The Programmer's Forum ................. Phone: (202) 966-3647 
  2173.           The Programmer's Forum is the home of the PNL.
  2174.  
  2175.           The Bored .............................. Phone: (512) 303-0471
  2176.  
  2177.           Classic City ........................... Phone: (404) 548-0726
  2178.  
  2179.           Theive's World ......................... Phone: (713) 463-8053
  2180.  
  2181.           Hippocampus ............................ Phone: (203) 484-4621
  2182.  
  2183.           Rogers State College BBS ............... Phone: (918) 341-8982
  2184.  
  2185.           The Foxtrot BBS ........................ Re-Locating
  2186.  
  2187.           Turbo City BBS ......................... Phone: (209) 599-7435
  2188.  
  2189.           Austin IEMUG/MIDI BBS .................. Phone: (512) 528-0626
  2190.  
  2191.           Laser Publishers ....................... Phone: (918) 438-2749
  2192.  
  2193.           Fargo RBBS-PC .......................... Phone: (701) 293-5973
  2194.  
  2195.